home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / UDP.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  7KB  |  308 lines

  1. /* Send and receive User Datagram Protocol packets */
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "udp.h"
  6. #include "ip.h"
  7. #include "internet.h"
  8. #include "icmp.h"
  9.  
  10. static struct udp_cb *lookup_udp __ARGS((struct socket *socket));
  11. static int16 hash_udp __ARGS((struct socket *socket));
  12.  
  13. /* Hash table for UDP structures */
  14. struct udp_cb *Udps[NUDP] = { NULLUDP} ;
  15. struct udp_stat Udp_stat;    /* Statistics */
  16.  
  17. /* Create a UDP control block for lsocket, so that we can queue
  18.  * incoming datagrams.
  19.  */
  20. struct udp_cb *
  21. open_udp(lsocket,r_upcall)
  22. struct socket *lsocket;
  23. void (*r_upcall)();
  24. {
  25.     register struct udp_cb *up;
  26.     int16 hval; 
  27.  
  28.     if((up = lookup_udp(lsocket)) != NULLUDP)
  29.         return up;    /* Already exists */
  30.     if((up = (struct udp_cb *)calloc(1,sizeof (struct udp_cb))) == NULLUDP){
  31.         Net_error = NO_MEM;
  32.         return NULLUDP;
  33.     }
  34.     up->socket.address = lsocket->address;
  35.     up->socket.port = lsocket->port;
  36.     up->r_upcall = r_upcall;
  37.  
  38.     hval = hash_udp(lsocket);
  39.     up->next = Udps[hval];
  40.     if(up->next != NULLUDP)
  41.         up->next->prev = up;
  42.     Udps[hval] = up;
  43.     return up;
  44. }
  45.  
  46. /* Send a UDP datagram */
  47. int
  48. send_udp(lsocket,fsocket,tos,ttl,data,length,id,df)
  49. struct socket *lsocket;        /* Source socket */
  50. struct socket *fsocket;        /* Destination socket */
  51. char tos;            /* Type-of-service for IP */
  52. char ttl;            /* Time-to-live for IP */
  53. struct mbuf *data;        /* Data field, if any */
  54. int16 length;            /* Length of data field */
  55. int16 id;            /* Optional ID field for IP */
  56. char df;            /* Don't Fragment flag for IP */
  57. {
  58.     struct mbuf *bp;
  59.     struct pseudo_header ph;
  60.     struct udp udp;
  61.  
  62.     length = UDPHDR;
  63.     if(data != NULLBUF)
  64.         length += len_mbuf(data);
  65.  
  66.     udp.source = lsocket->port;
  67.     udp.dest = fsocket->port;
  68.     udp.length = length;
  69.  
  70.     /* Create IP pseudo-header, compute checksum and send it */
  71.     ph.length = length;
  72.     ph.source = lsocket->address;
  73.     ph.dest = fsocket->address;
  74.     ph.protocol = UDP_PTCL;
  75.  
  76.     if((bp = htonudp(&udp,data,&ph)) == NULLBUF){
  77.         Net_error = NO_MEM;
  78.         free_p(data);
  79.         return 0;
  80.     }
  81.     Udp_stat.sent++;
  82.     ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,bp,length,id,df);
  83.     return length;
  84. }
  85. /* Accept a waiting datagram, if available. Returns length of datagram */
  86. int
  87. recv_udp(up,fsocket,bp)
  88. register struct udp_cb *up;
  89. struct socket *fsocket;        /* Place to stash incoming socket */
  90. struct mbuf **bp;        /* Place to stash data packet */
  91. {
  92.     struct socket *sp;
  93.     struct mbuf *buf;
  94.     int16 length;
  95.  
  96.     if(up == NULLUDP){
  97.         Net_error = NO_CONN;
  98.         return -1;
  99.     }
  100.     if(up->rcvcnt == 0){
  101.         Net_error = WOULDBLK;
  102.         return -1;
  103.     }
  104.     buf = dequeue(&up->rcvq);
  105.     up->rcvcnt--;
  106.  
  107.     sp = (struct socket *)buf->data;
  108.     /* Fill in the user's foreign socket structure, if given */
  109.     if(fsocket != NULLSOCK){
  110.         fsocket->address = sp->address;
  111.         fsocket->port = sp->port;
  112.     }
  113.     /* Strip socket header and hand data to user */
  114.     pullup(&buf,NULLCHAR,sizeof(struct socket));
  115.     length = len_mbuf(buf);
  116.     if(bp != (struct mbuf **)NULL)
  117.         *bp = buf;
  118.     else
  119.         free_p(buf);
  120.     return length;
  121. }
  122. /* Delete a UDP control block */
  123. int
  124. del_udp(up)
  125. struct udp_cb *up;
  126. {
  127.     struct mbuf *bp;
  128.     int16 hval;
  129.  
  130.     if(up == NULLUDP){
  131.         Net_error = INVALID;
  132.         return -1;
  133.     }        
  134.     /* Get rid of any pending packets */
  135.     while(up->rcvcnt != 0){
  136.         bp = up->rcvq;
  137.         up->rcvq = up->rcvq->anext;
  138.         free_p(bp);
  139.         up->rcvcnt--;
  140.     }
  141.     hval = hash_udp(&up->socket);
  142.     if(up->prev == NULLUDP)
  143.         Udps[hval] = up->next;        /* First on list */
  144.     else
  145.         up->prev->next = up->next;
  146.     if(up->next != NULLUDP)
  147.         up->next->prev = up->prev;
  148.  
  149.     free((char *)up);
  150.     return 0;
  151. }
  152. /* Process an incoming UDP datagram */
  153. void
  154. udp_input(bp,ip,rxbroadcast)
  155. struct mbuf *bp;    /* UDP header and data */
  156. struct ip *ip;        /* IP header */
  157. int rxbroadcast;    /* The only protocol that accepts 'em */
  158. {
  159.     struct pseudo_header ph;
  160.     struct udp udp;
  161.     struct udp_cb *up;
  162.     struct socket lsocket;
  163.     struct socket *fsocket;
  164.     struct mbuf *packet;
  165.     int ckfail = 0;
  166.     int16 length;
  167.  
  168.     if(bp == NULLBUF)
  169.         return;
  170.  
  171.     Udp_stat.rcvd++;
  172.  
  173.     /* Create pseudo-header and verify checksum */
  174.     ph.source = ip->source;
  175.     ph.dest = ip->dest;
  176.     ph.protocol = ip->protocol;
  177.     length = ip->length - IPLEN - ip->optlen;
  178.     ph.length = length;
  179.  
  180.     if(cksum(&ph,bp,length) != 0)
  181.         /* Checksum apparently failed, note for later */
  182.         ckfail++;
  183.  
  184.     /* Extract UDP header in host order */
  185.     ntohudp(&udp,&bp);
  186.  
  187.     /* If the checksum field is zero, then ignore a checksum error.
  188.      * I think this is dangerously wrong, but it is in the spec.
  189.      */
  190.     if(ckfail && udp.checksum != 0){
  191.         Udp_stat.cksum++;
  192.         free_p(bp);
  193.         return;
  194.     }
  195.     /* If this was a broadcast packet, pretend it was sent to us */
  196.     if(rxbroadcast){
  197.         lsocket.address = Ip_addr;
  198.         Udp_stat.bdcsts++;
  199.     } else
  200.         lsocket.address = ip->dest;
  201.  
  202.     lsocket.port = udp.dest;
  203.     /* See if there's somebody around to read it */
  204.     if((up = lookup_udp(&lsocket)) == NULLUDP){
  205.         /* Nope, return an ICMP message */
  206.         Udp_stat.unknown++;
  207.         if(!rxbroadcast){
  208.             bp = htonudp(&udp,bp,&ph);
  209.             icmp_output(ip,bp,DEST_UNREACH,PORT_UNREACH,NULL);
  210.         }
  211.         free_p(bp);
  212.         return;
  213.     }
  214.     /* Create space for the foreign socket info */
  215.     if((packet = pushdown(bp,sizeof(struct socket))) == NULLBUF){
  216.         /* No space, drop whole packet */
  217.         free_p(bp);
  218.         return;
  219.     }
  220.     fsocket = (struct socket *)packet->data;
  221.     fsocket->address = ip->source;
  222.     fsocket->port = udp.source;
  223.  
  224.     /* Queue it */
  225.     enqueue(&up->rcvq,packet);
  226.     up->rcvcnt++;
  227.     if(up->r_upcall)
  228.         (*up->r_upcall)(up,up->rcvcnt);
  229. }
  230. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  231. static
  232. struct udp_cb *
  233. lookup_udp(socket)
  234. struct socket *socket;
  235. {
  236.     register struct udp_cb *up;
  237.  
  238.     up = Udps[hash_udp(socket)];
  239.     while(up != NULLUDP){
  240.         if(memcmp((char *)socket,(char *)&up->socket,sizeof(struct socket)) == 0)
  241.             break;
  242.         up = up->next;
  243.     }
  244.     return up;
  245. }
  246.  
  247. /* Hash a UDP socket (address and port) structure */
  248. static
  249. int16
  250. hash_udp(socket)
  251. struct socket *socket;
  252. {
  253.     register unsigned int hval;
  254.  
  255.     /* Compute hash function on socket structure */
  256.     hval = hiword(socket->address);
  257.     hval ^= loword(socket->address);
  258.     hval ^= socket->port;
  259.     return hval % NUDP;
  260. }
  261. /* Convert UDP header in internal format to an mbuf in external format */
  262. struct mbuf *
  263. htonudp(udp,data,ph)
  264. struct udp *udp;
  265. struct mbuf *data;
  266. struct pseudo_header *ph;
  267. {
  268.     struct mbuf *bp;
  269.     register char *cp;
  270.     int16 checksum;
  271.  
  272.     /* Allocate UDP protocol header and fill it in */
  273.     if((bp = pushdown(data,UDPHDR)) == NULLBUF)
  274.         return NULLBUF;
  275.  
  276.     cp = bp->data;
  277.     cp = put16(cp,udp->source);    /* Source port */
  278.     cp = put16(cp,udp->dest);    /* Destination port */
  279.     cp = put16(cp,udp->length);    /* Length */
  280.     *cp++ = 0;            /* Clear checksum */
  281.     *cp-- = 0;
  282.  
  283.     /* All zeros and all ones is equivalent in one's complement arithmetic;
  284.      * the spec requires us to change zeros into ones to distinguish an
  285.       * all-zero checksum from no checksum at all
  286.      */
  287.     if((checksum = cksum(ph,bp,ph->length)) == 0)
  288.         checksum = 0xffffffff;
  289.     put16(cp,checksum);
  290.     return bp;
  291. }
  292. /* Convert UDP header in mbuf to internal structure */
  293. int
  294. ntohudp(udp,bpp)
  295. struct udp *udp;
  296. struct mbuf **bpp;
  297. {
  298.     char udpbuf[UDPHDR];
  299.  
  300.     if(pullup(bpp,udpbuf,UDPHDR) != UDPHDR)
  301.         return -1;
  302.     udp->source = get16(&udpbuf[0]);
  303.     udp->dest = get16(&udpbuf[2]);
  304.     udp->length = get16(&udpbuf[4]);
  305.     udp->checksum = get16(&udpbuf[6]);
  306.     return 0;
  307. }
  308.